// Copyright (C) 2022 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package dao

import (
	"context"
	dbutil "dist/db"
	"dist/model"
	"dist/utils"
	"fmt"
	"time"
)

func InsertRecord(record model.Record) bool {
	conn, _ := dbutil.GetConnection()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	businessType := utils.GetBusinessType(record.Event)
	result, err := conn.ExecContext(ctx, "INSERT INTO sp_records(ts, action, event, business_type, expand_id) VALUES($1,$2,$3,$4,$5)", record.Ts, record.Action, record.Event, businessType, record.ExpandId)
	defer conn.Close()
	if err != nil {
		utils.Error.Printf("Record is %v, insert error is %v", record, err)
		return false
	}
	if result != nil {
		return true
	}
	return true
}

func GetPageDistributionCount(startTime time.Time, endTime time.Time) []model.PageDistributionStruct {
	var pages []model.PageDistributionStruct
	conn, err := dbutil.GetConnection()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	rows, err := conn.QueryContext(ctx,
		`SELECT action,count(1) FROM sp_records  WHERE ts BETWEEN $1 AND $2  GROUP BY action order by count desc`,
		startTime, endTime)
	defer rows.Close()
	defer conn.Close()
	if err != nil {
		utils.Error.Printf("%v", err)
		return nil
	}
	for rows.Next() {
		var page model.PageDistributionStruct
		err = rows.Scan(&page.PageName, &page.AccessCount)
		if err != nil {
			utils.Error.Printf("%v", err)
			return nil
		}
		pages = append(pages, page)
	}
	return pages
}

func GetImportTraceCount(startTime time.Time, endTime time.Time, interval string) []model.ChartData {
	var pages []model.ChartData
	conn, err := dbutil.GetConnection()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	queryStr := utils.IMPORT_SQL
	queryStr = fmt.Sprintf(queryStr, interval)
	rows, err := conn.QueryContext(ctx, queryStr, startTime, endTime)
	defer rows.Close()
	defer conn.Close()
	if err != nil {
		utils.Error.Printf("sqlStr is %s, error is %v", queryStr, err)
		return nil
	}
	for rows.Next() {
		var page model.ChartData
		err = rows.Scan(&page.Date, &page.Value)
		if err != nil {
			utils.Error.Printf("%v", err)
			return nil
		}
		pages = append(pages, page)
	}
	return pages
}

func GetPageUseCount(startTime time.Time, endTime time.Time, interval string, action string) []model.ChartData {
	var chartDataList []model.ChartData
	conn, err := dbutil.GetConnection()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	querySql := fmt.Sprintf(utils.PAGE_USE_SQL, interval)
	rows, err := conn.QueryContext(ctx, querySql, startTime, endTime, action)
	defer rows.Close()
	defer conn.Close()
	if err != nil {
		utils.Error.Printf("sqlStr is %s, error is %v", querySql, err)
		return nil
	}
	for rows.Next() {
		var chartData model.ChartData
		err = rows.Scan(&chartData.Date, &chartData.Value)
		if err != nil {
			utils.Error.Printf("%v", err)
			return nil
		}
		chartDataList = append(chartDataList, chartData)
	}
	return chartDataList
}

func GetPluginsUse(startTime time.Time, endTime time.Time) []model.PluginsData {
	var chartDataList []model.PluginsData
	conn, err := dbutil.GetConnection()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	rows, err := conn.QueryContext(ctx, utils.GET_USE_PLUGIN_SQL, startTime, endTime)
	defer rows.Close()
	defer conn.Close()
	if err != nil {
		utils.Error.Printf("sqlStr is %s, error is %v", utils.GET_USE_PLUGIN_SQL, err)
		return nil
	}
	for rows.Next() {
		var chartData model.PluginsData
		err = rows.Scan(&chartData.PluginName, &chartData.UseCount)
		if err != nil {
			utils.Error.Printf("%v", err)
			return nil
		}
		chartDataList = append(chartDataList, chartData)
	}
	return chartDataList
}

func GetUse(startTime time.Time, endTime time.Time, interval string, action string, event string) []model.ChartData {
	var chartDataList []model.ChartData
	conn, err := dbutil.GetConnection()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	querySql := fmt.Sprintf(utils.GET_USE_SQL, interval)
	rows, err := conn.QueryContext(ctx, querySql, startTime, endTime, event, action)
	defer rows.Close()
	defer conn.Close()
	if err != nil {
		utils.Error.Printf("sqlStr is %s, error is %v", querySql, err)
		return nil
	}
	for rows.Next() {
		var chartData model.ChartData
		err = rows.Scan(&chartData.Date, &chartData.Value)
		if err != nil {
			utils.Error.Printf("%v", err)
			return nil
		}
		chartDataList = append(chartDataList, chartData)
	}
	return chartDataList
}

func GetRowAndTabCount(startTime time.Time, endTime time.Time, interval string) []model.RowData {
	var chartDataList []model.RowData
	conn, err := dbutil.GetConnection()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	rows, err := conn.QueryContext(ctx, utils.ROW_TAB_COUNT_SQL, startTime, endTime)
	defer rows.Close()
	defer conn.Close()
	if err != nil {
		utils.Error.Printf("sqlStr is %s, error is %v", utils.ROW_TAB_COUNT_SQL, err)
		return nil
	}
	for rows.Next() {
		var chartData model.RowData
		err = rows.Scan(&chartData.RowType, &chartData.Count)
		if err != nil {
			utils.Error.Printf("%v", err)
			return nil
		}
		chartDataList = append(chartDataList, chartData)
	}
	return chartDataList
}

func GetRowAndTabSubCount(startTime time.Time, endTime time.Time, interval string) []model.RowData {
	var chartDataList []model.RowData
	conn, err := dbutil.GetConnection()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	rows, err := conn.QueryContext(ctx, utils.ROW_TAB_SUB_COUNT_SQL, startTime, endTime)
	defer rows.Close()
	defer conn.Close()

	if err != nil {
		utils.Error.Printf("sqlStr is %s, error is %v", utils.ROW_TAB_SUB_COUNT_SQL, err)
		return nil
	}
	for rows.Next() {
		var chartData model.RowData
		err = rows.Scan(&chartData.SubType, &chartData.RowType, &chartData.Count)
		if err != nil {
			utils.Error.Printf("%v", err)
			return nil
		}
		chartDataList = append(chartDataList, chartData)
	}
	return chartDataList
}

func InsertGeneralRecord(record model.GeneralRecord) bool {
	conn, _ := dbutil.GetConnection()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	_, err := conn.ExecContext(ctx, "INSERT INTO sp_general_records_day(ts, category, second_cat, third_cat) VALUES($1,$2,$3,$4)", record.Ts, record.Category, record.SecondCat, record.ThirdCat)
	defer conn.Close()
	if err != nil {
		utils.Error.Printf("GeneralRecord is %v, insert error is %v", record, err)
		return false
	}
	return true
}

func IsTsInGeneralRecordTotalTbl(ts time.Time) bool {
	conn, _ := dbutil.GetConnection()
	defer conn.Close()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	rows, err := conn.QueryContext(ctx, "SELECT COUNT(*) FROM sp_general_records_total WHERE ts=$1", ts)
	if err != nil {
		utils.Error.Printf("IsTsInGeneralRecordTotalTbl: select min ts, error: %v", err)
		return true
	}
	defer rows.Close()
	if rows.Next() {
		var cnt int
		err = rows.Scan(&cnt)
		if err != nil {
			utils.Error.Printf("IsTsInGeneralRecordTotalTbl: scan max ts, error: %v", err)
			return true
		}
		if cnt == 0 {
			return false
		} else {
			return true
		}
	} else {
		return true
	}
}

func InsertGeneralRecordTotal(ts time.Time) {
	conn, _ := dbutil.GetConnection()
	defer conn.Close()
	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()
	_, err := conn.ExecContext(ctx, "INSERT INTO sp_general_records_total SELECT MIN(ts::DATE), category, second_cat, third_cat, count(*) AS cnt FROM sp_general_records_day WHERE (ts::DATE)=$1 GROUP BY category, second_cat, third_cat", ts)
	if err != nil {
		utils.Error.Printf("sp_general_records_total table insert failed, ts is %v, insert error is %v", ts, err)
		return
	}
}

func DeleteGeneralRecordDay(ts time.Time) {
	conn, _ := dbutil.GetConnection()
	defer conn.Close()
	ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
	defer cancel()
	_, err := conn.ExecContext(ctx, "DELETE FROM sp_general_records_day WHERE ts<=$1", ts)
	if err != nil {
		utils.Error.Printf("DeleteGeneralRecordDay delete failed, ts is %v, delete error is %v", ts, err)
		return
	}
}

func GetGeneralRecordUse(req model.GeneralQueryReq, startTime time.Time, endTime time.Time, interval, category string) []model.GeneralRecordData {
	var generalRecordDataList []model.GeneralRecordData
	conn, _ := dbutil.GetConnection()
	defer conn.Close()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	querySql := fmt.Sprintf(utils.GET_GENERAL_RECORD_USE1_SQL, interval, category, category)
	rows, err := conn.QueryContext(ctx, querySql, startTime, endTime)
	if err != nil {
		utils.Error.Printf("sqlStr is %s, error is %v", querySql, err)
		return nil
	}
	defer rows.Close()
	for rows.Next() {
		var generalRecordData model.GeneralRecordData
		err = rows.Scan(&generalRecordData.Date, &generalRecordData.Category, &generalRecordData.SecondCat, &generalRecordData.ThirdCat, &generalRecordData.Value)
		if err != nil {
			utils.Error.Printf("%v", err)
			return nil
		}
		generalRecordDataList = append(generalRecordDataList, generalRecordData)
	}
	return generalRecordDataList
}

func GetGeneralRecordUse2(req model.GeneralQueryReq, startTime time.Time, endTime time.Time, interval, category, secondCat string) []model.GeneralRecordData {
	var generalRecordDataList []model.GeneralRecordData
	conn, _ := dbutil.GetConnection()
	defer conn.Close()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	querySql := fmt.Sprintf(utils.GET_GENERAL_RECORD_USE2_SQL, interval, category, secondCat, category, secondCat)
	rows, err := conn.QueryContext(ctx, querySql, startTime, endTime)
	if err != nil {
		utils.Error.Printf("sqlStr is %s, error is %v", querySql, err)
		return nil
	}
	defer rows.Close()
	for rows.Next() {
		var generalRecordData model.GeneralRecordData
		err = rows.Scan(&generalRecordData.Date, &generalRecordData.Category, &generalRecordData.SecondCat, &generalRecordData.ThirdCat, &generalRecordData.Value)
		if err != nil {
			utils.Error.Printf("%v", err)
			return nil
		}
		generalRecordDataList = append(generalRecordDataList, generalRecordData)
	}
	return generalRecordDataList
}

func GetGeneralRecordUse3(req model.GeneralQueryReq, startTime time.Time, endTime time.Time, interval, category, secondCat, thirdCat string) []model.GeneralRecordData {
	var generalRecordDataList []model.GeneralRecordData
	conn, _ := dbutil.GetConnection()
	defer conn.Close()
	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
	defer cancel()
	querySql := fmt.Sprintf(utils.GET_GENERAL_RECORD_USE3_SQL, interval, category, secondCat, thirdCat, category, secondCat, thirdCat)
	rows, err := conn.QueryContext(ctx, querySql, startTime, endTime)
	if err != nil {
		utils.Error.Printf("sqlStr is %s, error is %v", querySql, err)
		return nil
	}
	defer rows.Close()
	for rows.Next() {
		var generalRecordData model.GeneralRecordData
		err = rows.Scan(&generalRecordData.Date, &generalRecordData.Category, &generalRecordData.SecondCat, &generalRecordData.ThirdCat, &generalRecordData.Value)
		if err != nil {
			utils.Error.Printf("%v", err)
			return nil
		}
		generalRecordDataList = append(generalRecordDataList, generalRecordData)
	}
	return generalRecordDataList
}
